﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using Tao.OpenGl;
using Tao.DevIl;
using AADD;
namespace MapEditor
{
    public partial class programWindow : Form
    {
        SpritesheetManager mapSpriteManager;  // Sprite manager for the map window... it has a different GL context from the tile window
        SpritesheetManager tileSpriteManager; // 
        Map map;

        public programWindow()
        {
            InitializeComponent();
            mapSpriteManager = new SpritesheetManager();
            tileSpriteManager = new SpritesheetManager();
            Il.ilInit();
            map = new Map("test.tga", 50, 50);

            setUpMapWindowScrollbars();
            mapWindowGL.MouseWheel += new MouseEventHandler(mapWindowGL_MouseWheel);
            tileWindowGL.MouseWheel += new MouseEventHandler(tileWindowGL_MouseWheel);

        }

        // Amount = how much to scroll
        // Delta is just checked for its sign: if positive, scroll down
        void scrollWheel(ScrollBar sb, int amount, int delta)
        {
            // I don't know why this code even has to exist.
            // A scrollbar's "Value" must ALWAYS be Minimum <= Value <= Maximum
            // so if you set it to -1 for example, it will immediately throw an exception.
            // Because of that, I do my own bounds-checking here.
            if (delta > 0)
                if (sb.Value < sb.Minimum + amount)
                    sb.Value = sb.Minimum;
                else
                    sb.Value -= amount;
            else if (delta < 0)
                if (sb.Value > (sb.Maximum - amount - sb.LargeChange))
                    sb.Value = sb.Maximum - sb.LargeChange + 1;
                else
                    sb.Value += amount;
        }

        void tileWindowGL_MouseWheel(object sender, MouseEventArgs e)
        {

            scrollWheel(tileVScroll, tileVScroll.SmallChange, e.Delta);

            // Finally, we send an event to the scroll-bar to trick it into thinking we scrolled so
            // that it can update whatever it has to
            tileVScroll_Scroll(sender, new ScrollEventArgs(ScrollEventType.SmallIncrement, tileVScroll.Value));
        }

        void mapWindowGL_MouseWheel(object sender, MouseEventArgs e)
        {
            scrollWheel(mapVScroll, mapVScroll.SmallChange, e.Delta );

            // Finally, we send an event to the scroll-bar to trick it into thinking we scrolled so
            // that it can update whatever it has to
            mapVScroll_Scroll(sender, new ScrollEventArgs(ScrollEventType.SmallIncrement, mapVScroll.Value));
        }

        private void programWindow_Load(object sender, EventArgs e)
        {
        }

        private void programWindow_Resize_1(object sender, EventArgs e)
        {
        }

        #region Log functions. They paste text to the console window
        private void logWithoutNewline(string text)
        {
            consoleWindow.AppendText(text);
            consoleWindow.ScrollToCaret();
        }

        private void logWithoutNewline(int text)
        {
            consoleWindow.AppendText(string.Format("{0}", text));
            consoleWindow.ScrollToCaret();
        }

        private void logWithNewline(string text)
        {
            consoleWindow.AppendText("\n" + text);
            consoleWindow.ScrollToCaret();
        }

        private void logWithNewline(int text)
        {
            consoleWindow.AppendText(string.Format("\n{0}", text));
            consoleWindow.ScrollToCaret();
        }
        #endregion

        private void setMapWindowMatrices()
        {
            Gl.glMatrixMode(Gl.GL_PROJECTION);
            Gl.glLoadIdentity();
            Glu.gluOrtho2D(0, mapWindowGL.Width, mapWindowGL.Height, 0);

            Gl.glMatrixMode(Gl.GL_VIEWPORT);
            Gl.glViewport(0, 0, mapWindowGL.Width, mapWindowGL.Height);
        }

        private void setTileWindowMatrices()
        {
            Gl.glMatrixMode(Gl.GL_PROJECTION);
            Gl.glLoadIdentity();
            Glu.gluOrtho2D(0, tileWindowGL.Width, tileWindowGL.Height, 0);

            Gl.glMatrixMode(Gl.GL_VIEWPORT);
            Gl.glViewport(0, 0, tileWindowGL.Width, tileWindowGL.Height);
        }

        private void mapWindowGL_Resize(object sender, EventArgs e)
        {
            // Every time the map window changes, we need to adjust the scroll-bars because more of the map could be visible
            setUpMapWindowScrollbars();
            setMapWindowMatrices();
        }

        private void setUpMapWindowScrollbars()
        {
            // Note: the scrollbar maxima need to be set before the Large/Small change
            // because  SmallChange << LargeChange << Maximum  at all times

            int arrowKeyScrollAmount = 1 * main.TILESIZE; // Clicking the up or down arrow when scrolling
            int pageUpScrollAmount = 5 * main.TILESIZE;   // Page-up / page-down when scrolling

            // The amount that you can scroll is equal to the amount of the map that isn't visible.
            // HOWEVER, the scroll-bar's size changes based on large change (and ONLY large change because
            // LargeChange is always greater than SmallChange)
            mapVScroll.Maximum = (map.height * main.TILESIZE - mapWindowGL.Height) + pageUpScrollAmount;
            mapHScroll.Maximum = (map.width * main.TILESIZE - mapWindowGL.Width) + pageUpScrollAmount;

            // Bounds-checking
            if (mapVScroll.Maximum < 0) mapVScroll.Maximum = 0;
            if (mapVScroll.Value > mapVScroll.Maximum) mapVScroll.Value = 0;
            if (mapHScroll.Maximum < 0) mapHScroll.Maximum = 0;
            if (mapHScroll.Value > mapHScroll.Maximum) mapHScroll.Value = 0;

            // Finally, we can change the LargeChange and SmallChange (in that order)
            // because of the "Small << Large << Maximum" rule
            mapVScroll.LargeChange = pageUpScrollAmount;
            mapHScroll.LargeChange = pageUpScrollAmount;

            mapVScroll.SmallChange = arrowKeyScrollAmount;
            mapHScroll.SmallChange = arrowKeyScrollAmount;
        }

        private void tileWindowGL_Resize(object sender, EventArgs e)
        {
            setTileWindowMatrices();
        }

        private void tileWindowGL_Load(object sender, EventArgs e)
        {
            this.tileWindowGL.InitializeContexts();
            Gl.glEnable(Gl.GL_BLEND);
            Gl.glBlendFunc(Gl.GL_SRC_ALPHA, Gl.GL_ONE_MINUS_SRC_ALPHA);			// Enable Alpha Blending (disable alpha testing)
            this.tileWindowGL.AutoMakeCurrent = true;
            Gl.glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
            Gl.glClear(Gl.GL_COLOR_BUFFER_BIT);


            Gl.glMatrixMode(Gl.GL_PROJECTION);
            Gl.glLoadIdentity();
            Glu.gluOrtho2D(0, tileWindowGL.Width, tileWindowGL.Height, 0);



            Gl.glMatrixMode(Gl.GL_MODELVIEW);
            Gl.glLoadIdentity();    
            Gl.glTranslatef(6, 6, 0);
            Gl.glBegin(Gl.GL_QUADS);
            Gl.glVertex2i(0, 0);
            Gl.glVertex2i(50, 0);
            Gl.glVertex2i(50, 50);
            Gl.glVertex2i(0, 50);
            Gl.glEnd();
        }

        private void mapWindowGL_Load(object sender, EventArgs e)
        {
            this.mapWindowGL.InitializeContexts();
            Gl.glEnable(Gl.GL_BLEND);
            Gl.glBlendFunc(Gl.GL_SRC_ALPHA, Gl.GL_ONE_MINUS_SRC_ALPHA);			// Enable Alpha Blending (disable alpha testing)
            this.mapWindowGL.AutoMakeCurrent = true;
            Gl.glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
            Gl.glClear(Gl.GL_COLOR_BUFFER_BIT);


            Gl.glMatrixMode(Gl.GL_PROJECTION);
            Gl.glLoadIdentity();
            Glu.gluOrtho2D(0, mapWindowGL.Width, mapWindowGL.Height, 0);



            Gl.glMatrixMode(Gl.GL_MODELVIEW);
            Gl.glLoadIdentity();
            Gl.glTranslatef(6, 6, 0);
            Gl.glBegin(Gl.GL_QUADS);
            Gl.glVertex2i(0, 0);
            Gl.glVertex2i(50, 0);
            Gl.glVertex2i(50, 50);
            Gl.glVertex2i(0, 50);
            Gl.glEnd();
        }

        private void mapWindowGL_Paint(object sender, PaintEventArgs e)
        {
            // Tao's context switching (SimpleOpenGlControl.MakeCurrent()) is costly,
            // so at the beginning of every context-specific command, we load in the two matrices that are
            // needed (projection and viewport). 
            // http://www.gamedev.net/community/forums/topic.asp?topic_id=406075
            // 
            setMapWindowMatrices();
            int scrollX = -this.mapHScroll.Value;
            int scrollY = -this.mapVScroll.Value;

            Gl.glMatrixMode(Gl.GL_MODELVIEW);

            Gl.glClear(Gl.GL_COLOR_BUFFER_BIT);

            Gl.glColor3ub(255, 255, 255);
            Gl.glMatrixMode(Gl.GL_MODELVIEW);
            Gl.glLoadIdentity();
            Gl.glTranslatef(scrollX, scrollY, 0);

            //Gl.glEnable(Gl.GL_ALPHA_TEST); //Enable alpha-blending
            //Gl.glAlphaFunc(Gl.GL_GREATER, 0.01f);
            map.blit(ref mapSpriteManager, 0, 0, 0, map.width, map.height);


            Gl.glFlush();
        }


        private void tileWindowGL_Paint(object sender, PaintEventArgs e)
        {
            setTileWindowMatrices();
            int scrollX = -this.tileHScroll.Value;
            int scrollY = -this.tileVScroll.Value;



            Gl.glClear(Gl.GL_COLOR_BUFFER_BIT);

            Gl.glColor3ub(255, 255, 0);
            Gl.glMatrixMode(Gl.GL_MODELVIEW);
            Gl.glLoadIdentity();
            Gl.glTranslatef(scrollX, scrollY, 0);
            //Gl.glBegin(Gl.GL_QUADS);
            //Gl.glVertex2i(0, 0);
            //Gl.glVertex2i(50, 0);
            //Gl.glVertex2i(50, 50);
            //Gl.glVertex2i(0, 50);
            //Gl.glEnd();
            tileSpriteManager.blit("test.tga", 0);


            Gl.glFlush();

        }


        private void mapHScroll_Scroll(object sender, ScrollEventArgs e)
        {
            mapWindowGL.Refresh();
        }

        private void mapVScroll_Scroll(object sender, ScrollEventArgs e)
        {
            //logWithNewline(string.Format("MapVScroll: {0}   Min: {1}    Max: {2} MapWindowHeight {3}", this.mapVScroll.Value, mapVScroll.Minimum, mapVScroll.Maximum,mapWindowGL.Height ));
            mapWindowGL.Refresh();
        }

        private void tileHScroll_Scroll(object sender, ScrollEventArgs e)
        {
            logWithNewline(string.Format("TileHScroll: {0}", this.tileHScroll.Value));
            tileWindowGL.Refresh();
        }

        private void tileVScroll_Scroll(object sender, ScrollEventArgs e)
        {
            logWithNewline(string.Format("TileVScroll: {0}", this.tileVScroll.Value));
            tileWindowGL.Refresh();
        }


        // This is only for one a window in the application receives a key press but does
        // not need to use it (like escape or hotkeys), so it's sent here to see if it's an
        // application-wide key. 
        private void keyPressed(char key)
        {
            switch (key)
            {
                case (char)27: // escape
                    Application.Exit();
                    break;
            }

        }


        private void tileWindowGL_KeyPress(object sender, KeyPressEventArgs e)
        {
            char key = e.KeyChar;
            switch (key)
            {
                default:
                    logWithNewline(string.Format("Key pressed: {0} coming from Tile Window, but unused, sending to main program", key));
                    keyPressed(key);
                    break;
            }

        }

        private void mapWindowGL_KeyPress(object sender, KeyPressEventArgs e)
        {
            char key = e.KeyChar;
            switch (key)
            {
                default:
                    logWithNewline(string.Format("Key pressed: {0} coming from Map Window, but unused, sending to main program", key));
                    keyPressed(key);
                    break;
            }
        }

        private void consoleWindow_KeyPress(object sender, KeyPressEventArgs e)
        {
            char key = e.KeyChar;
            switch (key)
            {
                default:
                    logWithNewline(string.Format("Key pressed: {0} coming from Console Window, but unused, sending to main program", key));
                    keyPressed(key);
                    break;
            }
        }

        private void exitToolStripMenuItem_Click(object sender, EventArgs e)
        {
            Application.Exit();
        }





    }
}
